/* tripl/arch/interp/arch_funcall.c 
 * 
 * This file is part of tripl. 
 * 
 * tripl is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * tripl is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with tripl. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <tripl/tripl.h>
#include <tripl/limits.h>


/* danger as your own risk */

int arch_funcall(void *p, struct arg_entry *args, int nargs) {
	register long result __asm__ ("ax");
	struct arg_entry *arg = args;

	int i;

	unsigned long arg_int[6] = { 0, 0, 0, 0, 0, 0 };
	unsigned long *args_linear = malloc((nargs - 6) << 3);


	for (i = 0; i < 6; i++) {
		if (!arg) 
			break;

		arg_int[i] = arg->arg_s ? (unsigned long) arg->arg_s : 
			(unsigned long) arg->arg_v;

		arg = arg->next;
	}


	for (i = 0; i < nargs - 6; i++) {
		if (!arg) 
			break;

		args_linear[i] = arg->arg_s ? (unsigned long) arg->arg_s : 
			(unsigned long) arg->arg_v;

		arg = arg->next;
	}

	/* 
	 * preparing arguments: 
	 * 	rdi 	rsi 	rdx 	rcx 	r8	r9 	stack 
	 * */

/*	__asm__ volatile (
		"cmpq 		$0, %%rdi\n\t"
		"je 		2f\n\t"
		"addq 		%2, %%rsp\n\t"
		"1:"
		"movq 		%1, %%rax\n\t"
		"movq 		(%%rdi, %%rax, 8), %%rcx\n\t"
		"pushq 		%%rcx\n\t"
		"subq 		$1, %%rax\n\t"
		"cmpq 		$0, %%rax\n\t"
		"jb 		1b\n\t"

		: "=D" (args_linear) : "r" ((long) nargs - 6), "r" ((long) (nargs - 6) << 3)
		: "ax", "cx"
	);*/

	__asm__ volatile (
		"2:"
		"movq 		%1, %%rdi\n\t"
		"movq 		%2, %%rsi\n\t"
		"movq 		%3, %%rdx\n\t"
		"movq 		%4, %%rcx\n\t"
		"movq 		%5, %%r8\n\t"
		"movq 		%6, %%r9\n\t"

		/* real calling: push returning address first and then 
		 * function address */ 

		"leaq 		1f(%%rip), %%rax\n\t"
		"pushq 		%%rax\n\t"
		"pushq		%0\n\t"
		"retq\n\t"
	
		"1:"

		:: "m" (p), 
		"m" (arg_int[0]), "m" (arg_int[1]), "m" (arg_int[2]), "m" (arg_int[3]), 
		"m" (arg_int[4]), "m" (arg_int[5])
		: "ax"
	);

	return result;
}


